<?php

namespace app\common\service;

use app\admin\model\yuncunchu\Config;
use app\admin\model\yuncunchu\File;
use think\Exception;
use think\Cache;

/**
 * 云存储服务类
 */
class YuncunchuService
{
    protected $config;
    protected $driver;
    protected $cache;

    public function __construct($configId = null)
    {
        $this->cache = Cache::init();
        
        if ($configId) {
            $this->config = $this->getConfig($configId);
        } else {
            $this->config = $this->getDefaultConfig();
        }
        
        if (!$this->config) {
            throw new Exception('未找到可用的存储配置');
        }
        
        $this->initDriver();
    }

    /**
     * 获取配置（带缓存）
     */
    protected function getConfig($configId)
    {
        $cacheKey = 'yuncunchu_config_' . $configId;
        $config = $this->cache->get($cacheKey);
        
        if (!$config) {
            $config = Config::find($configId);
            if ($config) {
                $this->cache->set($cacheKey, $config, 3600); // 缓存1小时
            }
        }
        
        return $config;
    }

    /**
     * 获取默认配置（带缓存）
     */
    protected function getDefaultConfig()
    {
        $cacheKey = 'yuncunchu_default_config';
        $config = $this->cache->get($cacheKey);
        
        if (!$config) {
            $config = Config::getDefaultConfig();
            if ($config) {
                $this->cache->set($cacheKey, $config, 3600); // 缓存1小时
            }
        }
        
        return $config;
    }

    /**
     * 初始化存储驱动
     */
    protected function initDriver()
    {
        switch ($this->config->type) {
            case 'local':
                $this->driver = new \app\common\service\driver\LocalDriver($this->config);
                break;
            case 'aliyun_oss':
                $this->driver = new \app\common\service\driver\AliyunOSSDriver($this->config);
                break;
            case 'tencent_cos':
                $this->driver = new \app\common\service\driver\TencentCOSDriver($this->config);
                break;
            case 'qiniu':
                $this->driver = new \app\common\service\driver\QiniuDriver($this->config);
                break;
            default:
                throw new Exception('不支持的存储类型：' . $this->config->type);
        }
    }

    /**
     * 上传文件
     */
    public function upload($file, $module = 'admin', $action = 'upload')
    {
        try {
            // 验证文件
            $this->validateFile($file);
            
            // 生成文件信息
            $fileInfo = $this->generateFileInfo($file);
            
            // 检查文件是否已存在（通过MD5）
            $existingFile = $this->checkFileExists($fileInfo['md5']);
            if ($existingFile) {
                return [
                    'success' => true,
                    'file_id' => $existingFile->id,
                    'file_url' => $existingFile->file_url,
                    'file_name' => $existingFile->file_name,
                    'original_name' => $existingFile->original_name,
                    'file_size' => $existingFile->file_size,
                    'file_type' => $existingFile->file_type,
                    'duplicate' => true
                ];
            }
            
            // 上传到存储
            $result = $this->driver->upload($file, $fileInfo);
            
            // 保存文件记录
            $fileRecord = $this->saveFileRecord($fileInfo, $result, $module, $action);
            
            // 清除相关缓存
            $this->clearCache();
            
            return [
                'success' => true,
                'file_id' => $fileRecord->id,
                'file_url' => $fileRecord->file_url,
                'file_name' => $fileRecord->file_name,
                'original_name' => $fileRecord->original_name,
                'file_size' => $fileRecord->file_size,
                'file_type' => $fileRecord->file_type
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * 检查文件是否已存在
     */
    protected function checkFileExists($md5)
    {
        return File::where('md5', $md5)->where('status', 1)->find();
    }

    /**
     * 删除文件
     */
    public function delete($fileId)
    {
        $file = File::find($fileId);
        if (!$file) {
            throw new Exception('文件不存在');
        }
        
        // 从存储中删除
        $this->driver->delete($file->file_path);
        
        // 删除数据库记录
        $file->delete();
        
        // 清除相关缓存
        $this->clearCache();
        
        return true;
    }

    /**
     * 获取文件URL（带缓存）
     */
    public function getUrl($fileId)
    {
        $cacheKey = 'yuncunchu_file_url_' . $fileId;
        $url = $this->cache->get($cacheKey);
        
        if (!$url) {
            $file = File::find($fileId);
            if ($file) {
                $url = $file->file_url;
                $this->cache->set($cacheKey, $url, 3600); // 缓存1小时
            } else {
                $url = '';
            }
        }
        
        return $url;
    }

    /**
     * 验证文件
     */
    protected function validateFile($file)
    {
        if (!$file->isValid()) {
            throw new Exception('文件上传失败');
        }
        
        // 检查文件大小
        $maxSizeConfig = config('upload.maxsize') ?: '10mb';
        $maxSize = $this->parseSize($maxSizeConfig);
        if ($file->getSize() > $maxSize) {
            throw new Exception('文件大小超过限制（最大允许：' . $maxSizeConfig . '）');
        }
        
        // 检查文件类型
        $mimetypeConfig = config('upload.mimetype') ?: 'jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3,webm';
        $allowedTypes = is_array($mimetypeConfig) ? $mimetypeConfig : explode(',', $mimetypeConfig);
        $mimeType = $file->getMime();
        $extension = strtolower($file->getOriginalExtension());
        
        $allowed = false;
        
        // 检查MIME类型
        foreach ($allowedTypes as $type) {
            $type = trim($type);
            if (fnmatch($type, $mimeType)) {
                $allowed = true;
                break;
            }
        }
        
        // 如果MIME类型检查失败，检查文件扩展名
        if (!$allowed) {
            foreach ($allowedTypes as $type) {
                $type = trim($type);
                if (strtolower($type) === $extension) {
                    $allowed = true;
                    break;
                }
            }
        }
        
        if (!$allowed) {
            throw new Exception('不支持的文件类型：' . $mimeType . '（允许的类型：' . implode(', ', $allowedTypes) . '）');
        }
    }

    /**
     * 解析文件大小字符串
     */
    protected function parseSize($size)
    {
        $size = strtolower(trim($size));
        
        // 检查是否有单位
        if (preg_match('/^(\d+)([kmg]?b?)$/i', $size, $matches)) {
            $number = (int)$matches[1];
            $unit = strtolower($matches[2]);
            
            switch ($unit) {
                case 'g':
                case 'gb':
                    return $number * 1024 * 1024 * 1024;
                case 'm':
                case 'mb':
                    return $number * 1024 * 1024;
                case 'k':
                case 'kb':
                    return $number * 1024;
                default:
                    return $number;
            }
        }
        
        // 如果没有匹配到单位，直接返回数字
        return (int)$size;
    }

    /**
     * 生成文件信息
     */
    protected function generateFileInfo($file)
    {
        $extension = strtolower($file->getOriginalExtension());
        $fileName = md5(uniqid(mt_rand(), true)) . '.' . $extension;
        $date = date('Y/m/d');
        
        // 安全地获取文件路径和哈希值
        $realPath = $file->getRealPath();
        $md5 = '';
        $sha1 = '';
        
        try {
            if ($realPath && file_exists($realPath) && is_readable($realPath)) {
                // 使用文件内容计算哈希（避免hash_file错误）
                $content = file_get_contents($realPath);
                if ($content !== false) {
                    $md5 = md5($content);
                    $sha1 = sha1($content);
                } else {
                    // 如果无法读取文件内容，使用备用方法
                    $md5 = md5($file->getInfo('name') . time() . rand());
                    $sha1 = sha1($file->getInfo('name') . time() . rand());
                }
            } else {
                // 使用文件内容计算哈希
                $content = $file->get();
                if ($content !== false) {
                    $md5 = md5($content);
                    $sha1 = sha1($content);
                } else {
                    // 如果无法获取内容，使用文件名和时间戳生成哈希
                    $md5 = md5($file->getInfo('name') . time() . rand());
                    $sha1 = sha1($file->getInfo('name') . time() . rand());
                }
            }
        } catch (Exception $e) {
            // 如果所有方法都失败，使用备用方法
            $md5 = md5($file->getInfo('name') . time() . rand());
            $sha1 = sha1($file->getInfo('name') . time() . rand());
        }
        
        return [
            'original_name' => $file->getInfo('name'),
            'file_name' => $fileName,
            'file_path' => $date . '/' . $fileName,
            'file_size' => $file->getSize(),
            'file_type' => $file->getMime(),
            'extension' => $extension,
            'md5' => $md5,
            'sha1' => $sha1
        ];
    }

    /**
     * 保存文件记录
     */
    protected function saveFileRecord($fileInfo, $result, $module, $action)
    {
        $data = [
            'config_id' => $this->config->id,
            'original_name' => $fileInfo['original_name'],
            'file_name' => $fileInfo['file_name'],
            'file_path' => $result['file_path'],
            'file_url' => $result['file_url'],
            'file_size' => $fileInfo['file_size'],
            'file_type' => $fileInfo['file_type'],
            'mime_type' => $fileInfo['file_type'],
            'extension' => $fileInfo['extension'],
            'md5' => $fileInfo['md5'],
            'sha1' => $fileInfo['sha1'],
            'upload_module' => $module,
            'upload_action' => $action,
            'user_id' => session('user.id'),
            'admin_id' => session('admin.id'),
            'status' => 1
        ];
        
        return File::create($data);
    }

    /**
     * 批量上传
     */
    public function batchUpload($files, $module = 'admin', $action = 'upload')
    {
        $results = [];
        
        // 确保$files是数组
        if (!is_array($files)) {
            $files = [$files];
        }
        
        foreach ($files as $file) {
            try {
                $results[] = $this->upload($file, $module, $action);
            } catch (Exception $e) {
                $results[] = [
                    'success' => false,
                    'message' => $e->getMessage()
                ];
            }
        }
        
        return $results;
    }

    /**
     * 获取存储统计信息（带缓存）
     */
    public function getStatistics()
    {
        $cacheKey = 'yuncunchu_statistics_' . $this->config->id;
        $stats = $this->cache->get($cacheKey);
        
        if (!$stats) {
            $totalFiles = File::where('config_id', $this->config->id)->count();
            $totalSize = File::where('config_id', $this->config->id)->sum('file_size');
            
            $stats = [
                'total_files' => $totalFiles,
                'total_size' => $totalSize,
                'total_size_text' => $this->formatBytes($totalSize)
            ];
            
            $this->cache->set($cacheKey, $stats, 1800); // 缓存30分钟
        }
        
        return $stats;
    }

    /**
     * 清除相关缓存
     */
    protected function clearCache()
    {
        // 清除配置缓存
        $this->cache->rm('yuncunchu_config_' . $this->config->id);
        $this->cache->rm('yuncunchu_default_config');
        
        // 清除统计缓存
        $this->cache->rm('yuncunchu_statistics_' . $this->config->id);
        
        // 清除文件URL缓存（这里可以更精确地清除特定文件的缓存）
        $this->cache->rm('yuncunchu_file_url_*');
    }

    /**
     * 格式化文件大小
     */
    protected function formatBytes($size, $precision = 2)
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB');
        for ($i = 0; $size > 1024 && $i < count($units) - 1; $i++) {
            $size /= 1024;
        }
        return round($size, $precision) . ' ' . $units[$i];
    }

    /**
     * 异步上传（队列处理）
     */
    public function asyncUpload($filePath, $module = 'admin', $action = 'upload')
    {
        // 这里可以集成队列系统，如Redis队列
        // 将上传任务加入队列，由后台进程处理
        
        $task = [
            'file_path' => $filePath,
            'module' => $module,
            'action' => $action,
            'config_id' => $this->config->id,
            'create_time' => time()
        ];
        
        // 示例：将任务加入Redis队列
        // Redis::lpush('yuncunchu_upload_queue', json_encode($task));
        
        return [
            'success' => true,
            'message' => '文件已加入上传队列',
            'task_id' => md5(json_encode($task))
        ];
    }

    /**
     * 根据URL删除文件
     */
    public function deleteByUrl($fileUrl)
    {
        try {
            // 从URL中提取文件路径
            $filePath = $this->extractFilePathFromUrl($fileUrl);
            if (!$filePath) {
                throw new Exception('无法从URL中提取文件路径');
            }
            
            // 查找文件记录
            $file = File::where('file_url', $fileUrl)->find();
            if (!$file) {
                throw new Exception('文件记录不存在');
            }
            
            // 删除云存储中的文件
            $driver = $this->getDriver();
            $result = $driver->delete($filePath);
            
            // 删除数据库记录
            $file->delete();
            
            // 清除缓存
            $this->clearCache();
            
            return [
                'success' => true,
                'message' => '删除成功'
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * 测试连接
     */
    public function test()
    {
        try {
            $driver = $this->getDriver();
            if (method_exists($driver, 'test')) {
                return $driver->test();
            } else {
                return [
                    'success' => true,
                    'message' => '连接正常',
                    'config' => [
                        'type' => $this->config->type,
                        'name' => $this->config->name
                    ]
                ];
            }
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * 从URL中提取文件路径
     */
    protected function extractFilePathFromUrl($fileUrl)
    {
        // 移除域名部分
        $domain = $this->config->config['domain'] ?? '';
        if ($domain && strpos($fileUrl, $domain) === 0) {
            $filePath = substr($fileUrl, strlen($domain));
        } else {
            // 如果没有配置域名，尝试从URL中提取路径
            $parsedUrl = parse_url($fileUrl);
            $filePath = $parsedUrl['path'] ?? '';
        }
        
        // 移除开头的斜杠
        $filePath = ltrim($filePath, '/');
        
        return $filePath;
    }
}
